import "./style/viewer.scss";
import { eventEnum } from "./enum/event_enum";

Cesium.Ion.defaultAccessToken =
	"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4MDQxOTQyYi1iNmI0LTQ4NzUtODgzNy1iMjcwODE4ZGZlNTkiLCJpZCI6MTY1OTMsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1NzA3Nzc5OTh9.a8wdusd6lqGbpsKpcvCFARaStzVlCRXrPldVJflZHxE";

const { Cartographic, Cesium3DTileset, ScreenSpaceEventType } = Cesium;
export default class Viewer extends Cesium.Viewer {
	constructor(
		domId,
		initPostion = [118, 32, 8e6, 0, -90, 0],
		is3D = true,
		mapCfg = undefined,
		token = "",
		duration
	) {
		super(domId, {
			// animation: false,
			baseLayerPicker: false,
			fullscreenButton: false,
			geocoder: false,
			homeButton: false,
			infoBox: false,
			sceneModePicker: false,
			selectionIndicator: false,
			timeline: false,
			navigationHelpButton: false,
			contextOptions: {
				id: "cesiumCanvas", // must
				webgl: {
					// 图片输出专用
					preserveDrawingBuffer: true,
					alpha: true,
				},
			},
			// skyBox: false,
			// skyAtmosphere: false,
			sceneMode: is3D
				? Cesium.SceneMode.SCENE3D
				: Cesium.SceneMode.SCENE2D,
		});

		this.token = token;

		// this.scene.globe.showGroundAtmosphere = false
		this.scene.globe.baseColor = Cesium.Color.fromCssColorString("#013a66"); // 设置地球颜色
		// this.scene.globe.baseColor = Cesium.Color.fromCssColorString('#161a1d') // 设置地球颜色
		this.scene.backgroundColor = Cesium.Color.fromBytes(1, 1, 1, 1);

		this._initPostion = initPostion;
		this.mapCfg = mapCfg;

		this.layersMap = new Map();
		this.primitivesMap = new Map();

		this._eventObj = {
			[eventEnum.LEFT_CLICK]: new Map(),
			[eventEnum.LEFT_DOUBLE_CLICK]: new Map(),
			[eventEnum.RIGHT_CLICK]: new Map(),
			[eventEnum.WHEEL]: new Map(),
			[eventEnum.MOUSE_MOVE]: new Map(),
			// [eventEnum.LEFT_UP]: new Map(),
			// [eventEnum.LEFT_DOWN]: new Map()
			[eventEnum.LEFT_DRAG]: new Map(),
		};

		this.layerInfoAry = []; // 底图的数组，用于外面切换图层
		this.is3D = is3D;

		this._handler = new Cesium.ScreenSpaceEventHandler(this.scene.canvas);
		this._initLayer();
		this.initViewer(duration);

		this._cesiumWidget._creditContainer.style.display = "none";

		this.scene.fxaa = false;
		this.scene.globe.maximumScreenSpaceError = 4 / 3;

		this.webMercatorProjection = new Cesium.WebMercatorProjection();

		this._handler.setInputAction(() => {
			this.trackedEntity = undefined;
		}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
		// this.scene.screenSpaceCameraController.tiltEventTypes = [];
	}

	/*
	 * 恢复
	 * flyTime:飞行时间 ，秒，false为直接定位
	 * */
	initViewer(duration = 1) {
		this.setView(this._initPostion, duration);
	}

	/*
	 * 视角定位
	 *postion：位置 [118, 33, 1000000]||[118, 33]
	 * isFly:是否飞行
	 * duration:飞行动画时间
	 * headingPitchRoll:[度，度，度]左右摇头、上下点头
	 * */
	setView(postion, duration = 0) {
		this.camera.flyTo({
			destination: Cesium.Cartesian3.fromDegrees(
				postion[0],
				postion[1],
				postion[2]
					? postion[2]
					: this.camera.positionCartographic.height
			), // 设置位置
			orientation: {
				heading: Cesium.Math.toRadians(postion[3] || 0),
				pitch: Cesium.Math.toRadians(postion[4] || -90),
				roll: Cesium.Math.toRadians(postion[5] || 0),
			},
			duration,
		});
	}

	// 获取当前视角信息（位置及倾斜角）
	getCurrentView() {
		const heading = Cesium.Math.toDegrees(this.camera.heading);
		const pitch = Cesium.Math.toDegrees(this.camera.pitch);
		const roll = Cesium.Math.toDegrees(this.camera.roll);
		const cartographic = this.camera.positionCartographic;
		const { height, longitude, latitude } = cartographic;

		const result = {
			height,
			longitude: Cesium.Math.toDegrees(longitude),
			latitude: Cesium.Math.toDegrees(latitude),
			heading,
			pitch,
			roll,
		};
		return result;
	}

	/*
	 * 添加点图层
	 * pointArr:点数据 [lon,lat,height]
	 * pointStyle:点样式 {color:FF0000,pixelSize:5}
	 * */
	addPointLayer(pointArr, pointStyle) {
		//  每个点都添加到PointPrimitiveCollection对象中
		const pointCollection = this.scene.primitives.add(
			new Cesium.PointPrimitiveCollection()
		);
		for (let i = 0; i < pointArr.length; i++) {
			const point = pointArr[i];
			pointCollection.add({
				position: Cesium.Cartesian3.fromDegrees(
					point[0],
					point[1],
					point[2] || 0
				),
				color: Cesium.Color.fromCssColorString(
					pointStyle.color || "#FF0000"
				),
				pixelSize: pointStyle.pixelSize || 5,
			});
		}
	}

	/*
	 * 添加线图层
	 * json:线geojson数据
	 * lineStyle:线样式 { width = 4, color = '1bf2f5' }
	 * */
	addLineLayer(json, lineStyle) {
		const instances = [];
		const { width = 4, color = "1bf2f5" } = lineStyle;
		for (let index = 0; index < json.features.length; index++) {
			const element = json.features[index];

			for (let j = 0; j < element.geometry.coordinates.length; j++) {
				const info = element.geometry.coordinates[j];
				instances.push(
					new Cesium.GeometryInstance({
						geometry: new Cesium.GroundPolylineGeometry({
							positions: Cesium.Cartesian3.fromDegreesArray(
								info.flat()
							),
							width,
						}),
						attributes: {
							color: new Cesium.ColorGeometryInstanceAttribute.fromColor(
								Cesium.Color.fromCssColorString(color)
							),
						},
					})
				);
			}
		}
		this.scene.primitives.add(
			new Cesium.GroundPolylinePrimitive({
				geometryInstances: instances,
				appearance: new Cesium.PolylineColorAppearance(),
				asynchronous: false,
			})
		);
	}

	// 初始化图层
	_initLayer() {
		const layers = this.mapCfg.layers;

		if (layers) {
			this.imageryLayers.removeAll();
			for (let index = 0; index < layers.length; index++) {
				const element = layers[index];
				let curLayer;

				if (element.type === "tdt") {
					const imageryProvider =
						new Cesium.WebMapTileServiceImageryProvider({
							url: element.url + this.token,
							subdomains: element.subdomains,
							maximumLevel: 19,
						});
					curLayer =
						this.imageryLayers.addImageryProvider(imageryProvider);
				} else {
					const imageryProvider =
						new Cesium.UrlTemplateImageryProvider({
							url: element.url,
							// layer: 'tdtVecBasicLayer',
							// style: 'default',
							// format: 'image/png',
							// tileMatrixSetID: 'GoogleMapsCompatible',
							minimumLevel: 3,
							maximumLevel: 18,
						});
					curLayer =
						this.imageryLayers.addImageryProvider(imageryProvider);
				}
				curLayer.show = element.show;
				curLayer.name = element.name;
				curLayer.id = element.id;
				curLayer.need = element.need;
				curLayer.isLabel = element.isLabel;
				curLayer.gamma = 0.66;
				this.layerInfoAry.push(curLayer);
			}
		} else {
			this.imageryLayers.get(0).name = "影像图";
			this.imageryLayers.get(0).id = "default";
			this.imageryLayers.get(0).gamma = 0.66;
			this.layerInfoAry.push(this.imageryLayers.get(0));
		}
	}

	/*
	 * 切换地图
	 * id:图层id
	 * need:图层对应标注id
	 * */
	switchLayer(id, need) {
		for (let index = 0; index < this.layerInfoAry.length; index++) {
			const layer = this.layerInfoAry[index];
			layer.show = layer.id === id || layer.id === need;
		}
	}

	/*
	 * 增加图层
	 * layer：图层
	 * */
	addLayer(id, layer) {
		this.removeLayer(id);

		this.layersMap.set(id, layer);
		this.imageryLayers.add(layer);
	}

	/*
	 * 增加primitive
	 * primitive：图层
	 * */
	addPrimitive(id, primitive) {
		if (this.primitivesMap.has(id)) {
			this.removePrimitive(id);
		}

		this.primitivesMap.set(id, primitive);
		return this.scene.primitives.add(primitive);
	}
	removePrimitive(id) {
		const primitive = this.primitivesMap.get(id);
		this.scene.primitives.remove(primitive);
	}

	/*
	 * 添加倾斜摄影
	 * */
	load3DTiles(id, tilesetOption) {
		if (this.primitivesMap.has(id)) {
			this.removePrimitive(id);
		}

		const tileset = new Cesium3DTileset(tilesetOption);
		this.addPrimitive(id, tileset);
		// this.zoomTo(tileset)
		return tileset;
	}

	/*
	 * 获取当前视野中心
	 * */
	getViewCentre() {
		return this._radiansToDegrees(this.camera._positionCartographic);
	}

	/*
	 * 地表弧度坐标转地表经纬度
	 * */
	_radiansToDegrees(radians) {
		return {
			longitude: Cesium.Math.toDegrees(radians.longitude),
			latitude: Cesium.Math.toDegrees(radians.latitude),
			height: radians.height,
		};
	}

	/*
	 * Cartesian2转Cartesian3
	 * */
	_Cartesian2ToCartesian3(Cartesian2, is3D) {
		let myCartesian3;
		if (is3D) {
			const ray = this.camera.getPickRay(Cartesian2);
			myCartesian3 = this.scene.globe.pick(ray, this.scene);
		} else {
			myCartesian3 = this.camera.pickEllipsoid(
				Cartesian2,
				this.scene.globe.ellipsoid
			);
		}
		return myCartesian3;
	}

	/*
	 * 增加事件
	 * */
	addEvent(name, type, callback, enable = true) {
		if (this._eventObj[type].size === 0) {
			switch (type) {
				case eventEnum.LEFT_CLICK:
					this._clickEvent();
					break;
				case eventEnum.LEFT_DOUBLE_CLICK:
					this._doubleClickEvent();
					break;
				case eventEnum.RIGHT_CLICK:
					this._rightClickEvent();
					break;
				case eventEnum.WHEEL:
					this._wheelEvent();
					break;
				case eventEnum.MOUSE_MOVE:
					this._mouseMoveEvent();
					break;
				// case eventEnum.LEFT_UP:
				//   this.leftUpEvent()
				//   break
				// case eventEnum.LEFT_DOWN:
				//   this.leftDOWNEvent()
				//   break
				case eventEnum.LEFT_DRAG:
					this.cameraLeftDrag();
			}
		}
		this._eventObj[type].set(name, {
			enable,
			fn: callback,
		});
	}

	/*
	 * 改变事件是否可用
	 * */
	changeEvent(name, type, enable) {
		if (this._eventObj[type].get(name)) {
			this._eventObj[type].get(name).enable = enable;
		}
	}

	/*
	 * 移除监听事件
	 * */
	removeEvent(name, type) {
		this._eventObj[type].delete(name);
		if (this._eventObj[type].size !== 0) {
			this._handler.removeInputAction(ScreenSpaceEventType[type]);
		}
	}

	/*
	 * 点击事件
	 * */
	_clickEvent() {
		this._handler.setInputAction((evt) => {
			if (this._eventObj[eventEnum.LEFT_CLICK].size < 1) {
				return;
			}
			if (!evt.position) {
				return;
			}

			const cartesian = this._Cartesian2ToCartesian3(
				evt.position,
				this._is3D
			);

			if (!cartesian) {
				return;
			}
			const cartographic = Cartographic.fromCartesian(cartesian);
			const mapPosition = this._radiansToDegrees(cartographic);

			this._eventObj[eventEnum.LEFT_CLICK].forEach((fnObj) => {
				if (fnObj && fnObj.enable) {
					fnObj.fn({
						cartographic,
						position: mapPosition,
						pickObj: this.scene.pick(evt.position)
							? this.scene.pick(evt.position).id
							: false,
						xy: evt.position,
						typhoonObj: this.scene.pick(evt.position)
							? this.scene.pick(evt.position)
							: false,
					});
				}
			});
		}, ScreenSpaceEventType[eventEnum.LEFT_CLICK]);
	}

	/*
	 * 双击事件
	 * */
	_doubleClickEvent() {
		this._handler.setInputAction((evt) => {
			if (this._eventObj[eventEnum.LEFT_DOUBLE_CLICK].size < 1) {
				return;
			}
			if (!evt.position) {
				return;
			}
			const cartesian = this._Cartesian2ToCartesian3(
				evt.position,
				this._is3D
			);
			if (!cartesian) {
				return;
			}
			const cartographic = Cartographic.fromCartesian(cartesian);
			const mapPosition = this._radiansToDegrees(cartographic);

			this._eventObj[eventEnum.LEFT_DOUBLE_CLICK].forEach((fnObj) => {
				if (fnObj && fnObj.enable) {
					fnObj.fn({
						position: mapPosition,
						pickObj: this.scene.pick(evt.position)
							? this.scene.pick(evt.position).id
							: false,
						xy: evt.position,
					});
				}
			});
		}, ScreenSpaceEventType[eventEnum.LEFT_DOUBLE_CLICK]);
	}

	/*
	 * 右击事件
	 * */
	_rightClickEvent() {
		this._handler.setInputAction((evt) => {
			if (this._eventObj[eventEnum.RIGHT_CLICK].size < 1) {
				return;
			}
			if (!evt.position) {
				return;
			}
			const cartesian = this._Cartesian2ToCartesian3(
				evt.position,
				this._is3D
			);
			if (!cartesian) {
				return;
			}
			const cartographic = Cartographic.fromCartesian(cartesian);
			const mapPosition = this._radiansToDegrees(cartographic);

			this._eventObj[eventEnum.RIGHT_CLICK].forEach((fnObj) => {
				if (fnObj && fnObj.enable) {
					fnObj.fn({
						position: mapPosition,
						pickObj: this.scene.pick(evt.position)
							? this.scene.pick(evt.position).id
							: false,
						xy: evt.position,
					});
				}
			});
		}, ScreenSpaceEventType[eventEnum.RIGHT_CLICK]);
	}

	/*
	 * 滚轮事件
	 * */
	_wheelEvent() {
		this._handler.setInputAction((evt) => {
			if (this._eventObj[eventEnum.WHEEL].size < 1) {
				return;
			}

			this._eventObj[eventEnum.WHEEL].forEach((fnObj) => {
				if (fnObj && fnObj.enable) {
					fnObj.fn(evt);
				}
			});
		}, ScreenSpaceEventType[eventEnum.WHEEL]);
	}

	/*
	 * 鼠标移动事件
	 * */
	_mouseMoveEvent() {
		this._handler.setInputAction((evt) => {
			// const ct = new Date().getTime();
			// if (this.timesTamp && ct - this.timesTamp < this.timeGap) {
			//   return;
			// } else {
			//   this.timesTamp = ct;
			// }

			if (this._eventObj[eventEnum.MOUSE_MOVE].size < 1) {
				return;
			}

			// const cartesian = this._Cartesian2ToCartesian3(
			//   evt.endPosition,
			//   this._is3D
			// );
			// if (!cartesian) {
			//   return;
			// }
			const ray = this.camera.getPickRay(evt.endPosition);
			const cartesian = this.scene.globe.pick(ray, this.scene);

			if (!cartesian) {
				return;
			}
			const ellipsoid = this.scene.globe.ellipsoid;
			const cartographic = ellipsoid.cartesianToCartographic(cartesian);
			const latitude = CMath.toDegrees(cartographic.latitude);
			const longitude = CMath.toDegrees(cartographic.longitude);
			const height = cartographic.height;
			const mapPosition = {
				height,
				latitude,
				longitude,
			};
			this._eventObj[eventEnum.MOUSE_MOVE].forEach((fnObj) => {
				if (fnObj && fnObj.enable) {
					fnObj.fn(mapPosition);
				}
			});
		}, ScreenSpaceEventType[eventEnum.MOUSE_MOVE]);
	}

	// 获取视野范围
	getCurBDInfo() {
		// todo 二维场景？
		const widthCanvas = this.scene.canvas.clientWidth;
		const heitCanvas = this.scene.canvas.clientHeight;
		const ellipsoid = this.scene.globe.ellipsoid;
		const _this = this;
		function _getLonLat(x, y) {
			const car3 = _this.camera.pickEllipsoid(
				new Cesium.Cartesian2(x, y),
				ellipsoid
			);
			if (car3) {
				const cartographic = Cesium.Cartographic.fromCartesian(car3);
				return {
					lon: Cesium.Math.toDegrees(cartographic.longitude),
					lat: Cesium.Math.toDegrees(cartographic.latitude),
				};
			} else {
				return null;
			}
		}

		const lonlat_center = _getLonLat(widthCanvas / 2, heitCanvas / 2);
		const lonlat_lt = _getLonLat(0, 0);
		const lonlat_rt = _getLonLat(widthCanvas, 0);
		const lonlat_lb = _getLonLat(0, heitCanvas);
		const lonlat_rb = _getLonLat(widthCanvas, heitCanvas);
		const heitCamara = ellipsoid.cartesianToCartographic(
			this.camera.position
		).height;

		let lonCenter, latCenter, lonMin, lonMax, latMin, latMax;
		let isSpan180 = false;
		let lonMax2 = 180;
		// 中心
		if (lonlat_center) {
			lonCenter = lonlat_center.lon;
			latCenter = lonlat_center.lat;
		} else {
			lonCenter = 0;
			latCenter = 0;
		}
		// 左上角
		if (lonlat_lt) {
			lonMin = lonlat_lt.lon;
			latMax = lonlat_lt.lat;
		} else {
			lonMin = -180;
			latMax = 90;
		}
		// 右上角
		if (lonlat_rt) {
			lonMax = lonlat_rt.lon;
			if (latMax < lonlat_rt.lat) {
				latMax = lonlat_rt.lat;
			}
		} else {
			lonMax = 180;
		}
		// 左下角
		if (lonlat_lb) {
			if (lonMin > lonlat_lb.lon) {
				lonMin = lonlat_lb.lon;
			}
			latMin = lonlat_lb.lat;
		} else {
			latMin = -90;
		}
		// 右下角
		if (lonlat_rb) {
			if (lonMax < lonlat_rb.lon) {
				lonMax = lonlat_rb.lon;
			}
			if (latMin > lonlat_rb.lat) {
				latMin = lonlat_rb.lat;
			}
		}

		// todo 简单判断 取中心y点 x=0 --> widthCanvas 出现到180再减小 则跨180度
		if (lonMax < lonMin) {
			isSpan180 = true;
			lonMax2 = lonMax;
			lonMax = 180;
		}

		return {
			LonMin: lonMin,
			LonMax: lonMax,
			LatMin: latMin,
			LatMax: latMax,
			IsSpan180: isSpan180,
			LonMax2: lonMax2,
			MapCenterLon: lonCenter,
			MapCenterLat: latCenter,
			MapCenterAlt: heitCamara,
			Width: widthCanvas,
			Height: heitCanvas,
		};
	}
}
